home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / AmigaOS / scsi_amiga.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-05-24  |  6.5 KB  |  270 lines

  1. /*
  2.  *  scsi_amiga.cpp - SCSI Manager, Amiga specific stuff
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. #include <exec/types.h>
  22. #include <exec/memory.h>
  23. #include <devices/trackdisk.h>
  24. #include <devices/scsidisk.h>
  25. #include <proto/exec.h>
  26.  
  27. #include "sysdeps.h"
  28. #include "main.h"
  29. #include "prefs.h"
  30. #include "user_strings.h"
  31. #include "scsi.h"
  32.  
  33. #define DEBUG 0
  34. #include "debug.h"
  35.  
  36.  
  37. // Global variables
  38. static struct SCSICmd scsi;
  39.  
  40. static IOStdReq *ios[8*8];                // IORequests for 8 units and 8 LUNs each
  41. static IOStdReq *io;                    // Active IORequest (selected target)
  42.  
  43. static struct MsgPort *the_port = NULL;    // Message port for device communication
  44.  
  45. static ULONG buffer_size;                // Size of data buffer
  46. static UBYTE *buffer = NULL;            // Pointer to data buffer
  47. static ULONG buffer_memf;                // Buffer memory flags
  48.  
  49. static UBYTE cmd_buffer[12];            // Buffer for SCSI command
  50.  
  51. const int SENSE_LENGTH = 256;
  52. static UBYTE *sense_buffer = NULL;        // Buffer for autosense data
  53.  
  54.  
  55. /*
  56.  *  Initialization
  57.  */
  58.  
  59. void SCSIInit(void)
  60. {
  61.     int id, lun;
  62.  
  63.     int memtype = PrefsFindInt32("scsimemtype");
  64.     switch (memtype) {
  65.         case 1:
  66.             buffer_memf = MEMF_24BITDMA | MEMF_PUBLIC;
  67.             break;
  68.         case 2:
  69.             buffer_memf = MEMF_ANY | MEMF_PUBLIC;
  70.             break;
  71.         default:
  72.             buffer_memf = MEMF_CHIP | MEMF_PUBLIC;
  73.             break;
  74.     }
  75.  
  76.     // Create port and buffers
  77.     the_port = CreateMsgPort();
  78.     buffer = (UBYTE *)AllocMem(buffer_size = 0x10000, buffer_memf);
  79.     sense_buffer = (UBYTE *)AllocMem(SENSE_LENGTH, MEMF_CHIP | MEMF_PUBLIC);
  80.     if (the_port == NULL || buffer == NULL || sense_buffer == NULL) {
  81.         ErrorAlert(GetString(STR_NO_MEM_ERR));
  82.         QuitEmulator();
  83.     }
  84.  
  85.     // Create and open IORequests for all 8 units (and all 8 LUNs)
  86.     for (id=0; id<8; id++) {
  87.         for (lun=0; lun<8; lun++)
  88.             ios[id*8+lun] = NULL;
  89.         char prefs_name[16];
  90.         sprintf(prefs_name, "scsi%d", id);
  91.         const char *str = PrefsFindString(prefs_name);
  92.         if (str) {
  93.             char dev_name[256];
  94.             ULONG dev_unit = 0;
  95.             if (sscanf(str, "%[^/]/%ld", dev_name, &dev_unit) == 2) {
  96.                 for (lun=0; lun<8; lun++) {
  97.                     struct IOStdReq *io = (struct IOStdReq *)CreateIORequest(the_port, sizeof(struct IOStdReq));
  98.                     if (io == NULL)
  99.                         continue;
  100.                     if (OpenDevice((UBYTE *)dev_name, dev_unit + lun * 10, (struct IORequest *)io, 0)) {
  101.                         DeleteIORequest(io);
  102.                         continue;
  103.                     }
  104.                     io->io_Data = &scsi;
  105.                     io->io_Length = sizeof(scsi);
  106.                     io->io_Command = HD_SCSICMD;
  107.                     ios[id*8+lun] = io;
  108.                 }
  109.             }
  110.         }
  111.     }
  112.  
  113.     // Reset SCSI bus
  114.     SCSIReset();
  115.  
  116.     // Init SCSICmd
  117.     memset(&scsi, 0, sizeof(scsi));
  118.     scsi.scsi_Command = cmd_buffer;
  119.     scsi.scsi_SenseData = sense_buffer;
  120.     scsi.scsi_SenseLength = SENSE_LENGTH;
  121. }
  122.  
  123.  
  124. /*
  125.  *  Deinitialization
  126.  */
  127.  
  128. void SCSIExit(void)
  129. {
  130.     // Close all devices
  131.     for (int i=0; i<8; i++)
  132.         for (int j=0; j<8; j++) {
  133.             struct IOStdReq *io = ios[i*8+j];
  134.             if (io) {
  135.                 CloseDevice((struct IORequest *)io);
  136.                 DeleteIORequest(io);
  137.             }
  138.         }
  139.  
  140.     // Delete port and buffers
  141.     if (the_port)
  142.         DeleteMsgPort(the_port);
  143.     if (buffer)
  144.         FreeMem(buffer, buffer_size);
  145.     if (sense_buffer)
  146.         FreeMem(sense_buffer, SENSE_LENGTH);
  147. }
  148.  
  149.  
  150. /*
  151.  *  Check if requested data size fits into buffer, allocate new buffer if needed
  152.  */
  153.  
  154. static bool try_buffer(int size)
  155. {
  156.     if (size <= buffer_size)
  157.         return true;
  158.  
  159.     UBYTE *new_buffer = (UBYTE *)AllocMem(size, buffer_memf);
  160.     if (new_buffer == NULL)
  161.         return false;
  162.     FreeMem(buffer, buffer_size);
  163.     buffer = new_buffer;
  164.     buffer_size = size;
  165.     return true;
  166. }
  167.  
  168.  
  169. /*
  170.  *  Set SCSI command to be sent by scsi_send_cmd()
  171.  */
  172.  
  173. void scsi_set_cmd(int cmd_length, uint8 *cmd)
  174. {
  175.     scsi.scsi_CmdLength = cmd_length;
  176.     memcpy(cmd_buffer, cmd, cmd_length);
  177. }
  178.  
  179.  
  180. /*
  181.  *  Check for presence of SCSI target
  182.  */
  183.  
  184. bool scsi_is_target_present(int id)
  185. {
  186.     return ios[id * 8] != NULL;
  187. }
  188.  
  189.  
  190. /*
  191.  *  Set SCSI target (returns false on error)
  192.  */
  193.  
  194. bool scsi_set_target(int id, int lun)
  195. {
  196.     struct IOStdReq *new_io = ios[id * 8 + lun];
  197.     if (new_io == NULL)
  198.         return false;
  199.     if (new_io != io)
  200.         scsi.scsi_SenseActual = 0;    // Clear sense data when selecting new target
  201.     io = new_io;
  202.     return true;
  203. }
  204.  
  205.  
  206. /*
  207.  *  Send SCSI command to active target (scsi_set_command() must have been called),
  208.  *  read/write data according to S/G table (returns false on error); timeout is in 1/60 sec
  209.  */
  210.  
  211. bool scsi_send_cmd(size_t data_length, bool reading, int sg_size, uint8 **sg_ptr, uint32 *sg_len, uint16 *stat, uint32 timeout)
  212. {
  213.     // Check if buffer is large enough, allocate new buffer if needed
  214.     if (!try_buffer(data_length)) {
  215.         char str[256];
  216.         sprintf(str, GetString(STR_SCSI_BUFFER_ERR), data_length);
  217.         ErrorAlert(str);
  218.         return false;
  219.     }
  220.  
  221.     // Process S/G table when writing
  222.     if (!reading) {
  223.         D(bug(" writing to buffer\n"));
  224.         uint8 *buffer_ptr = buffer;
  225.         for (int i=0; i<sg_size; i++) {
  226.             uint32 len = sg_len[i];
  227.             D(bug("  %d bytes from %08lx\n", len, sg_ptr[i]));
  228.             memcpy(buffer_ptr, sg_ptr[i], len);
  229.             buffer_ptr += len;
  230.         }
  231.     }
  232.  
  233.     // Request Sense and autosense data valid?
  234.     BYTE res = 0;
  235.     if (cmd_buffer[0] == 0x03 && scsi.scsi_SenseActual) {
  236.  
  237.         // Yes, fake command
  238.         D(bug(" autosense\n"));
  239.         memcpy(buffer, sense_buffer, scsi.scsi_SenseActual);
  240.         scsi.scsi_Status = 0;
  241.  
  242.     } else {
  243.  
  244.         // No, send regular command
  245.         D(bug(" sending command, length %ld\n", data_length));
  246.         scsi.scsi_Data = (UWORD *)buffer;
  247.         scsi.scsi_Length = data_length;
  248.         scsi.scsi_Actual = 0;
  249.         scsi.scsi_Flags = (reading ? SCSIF_READ : SCSIF_WRITE) | SCSIF_AUTOSENSE;
  250.         scsi.scsi_SenseActual = 0;
  251.         scsi.scsi_Status = 0;
  252.         res = DoIO((struct IORequest *)io);
  253.         D(bug(" command sent, res %d, status %d\n", res, scsi.scsi_Status));
  254.         *stat = scsi.scsi_Status;
  255.     }
  256.  
  257.     // Process S/G table when reading
  258.     if (reading && res == 0) {
  259.         D(bug(" reading from buffer\n"));
  260.         uint8 *buffer_ptr = buffer;
  261.         for (int i=0; i<sg_size; i++) {
  262.             uint32 len = sg_len[i];
  263.             D(bug("  %d bytes to %08lx\n", len, sg_ptr[i]));
  264.             memcpy(sg_ptr[i], buffer_ptr, len);
  265.             buffer_ptr += len;
  266.         }
  267.     }
  268.     return res == 0;
  269. }
  270.